/*
*    Clean AJAX Engine v4.0
*    Copyright (C) 2005-2006 Carlos Eduardo Goncalves (cadu.goncalves@gmail.com)
*
*    This program is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program; if not, write to the Free Software
*    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

/**
* Class based on adapter design pattern used to adapt 
* messages with objects provided by the browser.
* @author Carlos Eduardo Goncalves
*/

/**
* <p>Message wrapper constructor.</p>
*/
function MessageWrapper(){
  /** <p>Holds a XSL file that will be used to parse the response.</p> */
  MessageWrapper.prototype.style = null; 
  /** <p>Holds message unique id.</p> */  
  MessageWrapper.prototype.id = null;   
  /** <p>Holds message consumer element id.</p> */
  MessageWrapper.prototype.consumer = null; 
  /** <p>Flag that defines if consumer value will be refreshed.</p> */
  MessageWrapper.prototype.refresh = null;
  /** <p>Document used to find the message consumer element.</p> */
  MessageWrapper.prototype.doc = null; 
  /** <p>URL to request.</p> */
  MessageWrapper.prototype.address = null;	
  /** <p>Flag that defines if the message will display any progress bar.</p> */
  MessageWrapper.prototype.silent = null;
  /** <p>Holds the progress bar used by the message.</p> */
  MessageWrapper.prototype.progressBar = null;
  /** <p>Holds a <code>RemoteMethod</code> defined as value of the message.</p> */
  MessageWrapper.prototype.remoteMethod = null;
  /** <p>Holds a <code>RemoteMethod</code> parsed to XML.</p> */
  MessageWrapper.prototype.parsedMethod = null;	
  /** <p>Holds the XMLHttpRequest instance used to perform to send the request.</p> */
  MessageWrapper.prototype.request = null;
  /** <p>Event handler called when a exception occurs.</p> */
  MessageWrapper.prototype.onError = null;
  /** <p>Event handler called after response.</p> */
  MessageWrapper.prototype.onComplete = null;  
}

/** 
* <p>Import all AJAX message data to the wrapper.</p>
* @param msg
*		<code>Message</code> value object to be wrapped.	
* @throws Exception that informs if the parameter is not a <code>Message</code> object.
*/
MessageWrapper.prototype.wrap = function(msg){
  try{	
	if(!Engine.assertType(msg, Message))
	  throw "Invalid parameter";
	if(Engine.HTTP_METHODS.toString().indexOf(msg.method.toUpperCase()) == -1)
	  msg.method = "POST";	
    if(msg.xslt != null)
	  this.style = Engine.loadFile(msg.xslt);   	
    this.id = MessageQueue.messages.length;   
	this.consumer = msg.consumer; 
	this.refresh = msg.refresh;
    this.doc = msg.doc; 
	this.address = msg.address;	
	this.silent = msg.silent;
    this.progressBar = msg.progressBar;
	if(Engine.assertType(msg.value, RemoteMethod)){
      var stream = this.getStream(msg.value.protocol); 	  
 	  if(stream){
	    this.remoteMethod = msg.value;
        this.parsedMethod = stream.write(this.remoteMethod);	
	  }
	}  
    this.request = Engine.buildRequest();
    this.request.open(msg.method, msg.address);
    this.onError = msg.onError;
    this.onComplete = msg.onComplete;	
    if(msg.onChange != null)
	  this.request.onreadystatechange = msg.onChange;   
    else{ 
	  var _this = this;
	  var args = [this];
	  this.request.onreadystatechange = function() {
    		_this.onChange.apply(args[0], args);
  		}
    }
  } catch(e){Engine.reportException(null, e);}
}

/** 
* <p>Create an appropriate stream to read a XML document.</p>
* @param format
*		XML document format (XMLRPC or SOAP).
* @return
*		Valid stream object or <code>null</code>.
*/
MessageWrapper.prototype.getStream = function(format){ 
  if(!format)
    return null;
  switch(format.toUpperCase()){
	case 'SOAP':
	  return new SoapStream();
	case 'XMLRPC':
	  return new XmlRpcStream();
	default: 
	  return null;
  }
}

/** 
* <p>Internal onreadystatechange listener used by <code>Message</code> instances.</p>
*/
MessageWrapper.prototype.onChange = function(){ 
  try{
    if(this.request.readyState == 4){	
	  if(this.remoteMethod)
	    Engine.doAsPrivileged();
      var s = this.parseStatus(this.request.status)  + ": " + this.address;
      Console.trace(s, Console.RESPONSE);			  
      if(this.request.status >= 200 && this.request.status <= 299){		
	    var iterator = new DomIterator(this.doc);
	    if(this.style != null)
	      iterator.applyValue(this.consumer, XsltTool.transform(this.request.responseXML, this.style), this.refresh);
	    else{
	      if(this.remoteMethod){
		    var stream = this.getStream(this.remoteMethod.protocol);
			if(stream){
              Console.trace(this.request.responseText, Console.RPC_DATA);				
			  var rpcResult = stream.read(this.request.responseXML);
			  if(stream.faultValue){
			    if(this.remoteMethod.onError)			  
			      this.remoteMethod.onError(rpcResult);
			  }
			  else{
			    if(this.remoteMethod.onResult)
			      this.remoteMethod.onResult(rpcResult);
			  }
			}
		  }
		  else
		    iterator.applyValue(this.consumer, this.request.responseText, this.refresh);
		}
      }  	  
	  if(this.progressBar)
  	    this.progressBar.update(false);	  
      if(this.onComplete != null)
	    this.onComplete(this.request); 		
      MessageQueue.remove(this.id);		
    }
  } catch(e){Engine.reportException(null, e);}  
}  	  

/**
* <p>Return user friendly HTTP status code.</p>
* @param status
*		Status code.
* @return
*		<code>String</code> with the request status and its definition.
*/
MessageWrapper.prototype.parseStatus = function(status){ 
  try{
    var str = "HTTP status " + status;
    for(var i = 0; i < Engine.HTTP_STATUS_CODES.length; ++i){
      if(Engine.HTTP_STATUS_CODES[i].indexOf(status) != -1){
	    str = Engine.HTTP_STATUS_CODES[i];	
	    break;
	  }
    }
    return str;
  } catch(e){Engine.reportException(null, e);}    
}
